/* Tic-tac-toe.
 * 
 * julio 2.008
 * 
 * Propuesta de programación en el foro:
 * http://www.forosdelweb.com/f14/por-que-no-hacemos-competencia-entre-programadores-600799/
 * 
 * 
 */
package ttt;

import errores.BOOMException;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import utils.Imagenes;
import utils.Sonidos;

/**
 *
 * @author Fénix
 */
public class TicTacToe extends JFrame implements MouseListener, MouseMotionListener {

	public static final int RPS = 30;
	
	public static final int ANCHO = 640;
	public static final int ALTO = 505;
	public static final int JUGANDOSE = 2;
	public static final int GANAX = -1;
	public static final int GANAO = 1;
	public static final int EMPATE = 0;
	
	//Posición de los marcadores
	private final int MARCADOR_JUGADOR_X = 514;
	private final int MARCADOR_JUGADOR_Y = 163;
	private final int MARCADOR_ORDENADOR_X = 518;
	private final int MARCADOR_ORDENADOR_Y = 351;
	
	private final int BOTON_SALIR_X = 593;
	private final int BOTON_SALIR_Y = 457;
	
	private final int BOTON_FACIL_X = 145;
	private final int BOTON_FACIL_Y = 350;
	private final int BOTON_DIFICIL_X = 360;
	private final int BOTON_DIFICIL_Y = 336;
	
	private final int MINI_JUGADOR_X = 555;
	private final int MINI_JUGADOR_Y = 125;
	private final int MINI_OPONENTE_X = 550;
	private final int MINI_OPONENTE_Y = 325;
	
	private final int MENSAJE_X = 49;
	private final int MENSAJE_Y = 170;
	
	private long tiempoInicio;
	
	private boolean jugando;
	private boolean salir;
	private Imagenes imagenes = null;
	private Sonidos sonidos = null;
	private Tablero tablero = null;
	private BufferStrategy buffer = null;
	private Oponente oponente = null;
	
	private String fichaJugador;
	
	private int resultadoPartida;
	private boolean turnoJugador;
	
	private int partidasGanadasJugador;
	private int partidasGanadasOrdenador;
	
	private boolean esperandoEleccion;
	private boolean facilOn;
	private boolean dificilOn;
	
	private boolean esperandoClick;
	
	
	public TicTacToe() {
		super("Tic Tac Toe");

		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(ANCHO, ALTO);
		this.setResizable(false);
		this.setUndecorated(true);
		
		GraphicsEnvironment environ = GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice device = environ.getDefaultScreenDevice();
		if (device.isFullScreenSupported()) {
			System.out.println("Pantalla completa soportada...");
			device.setFullScreenWindow(this);
		} else {
			System.out.println("Pantalla completa no soportada...");
		}
		
		this.setVisible(true);

		this.createBufferStrategy(2);
		buffer = getBufferStrategy();

		this.addMouseListener(this);
		this.addMouseMotionListener(this);

		imagenes = new Imagenes();
		sonidos = new Sonidos();

	}

	private void salirJuego(int salida) {
		System.exit(salida);
	}
	
	private String convertirNumeroCadena(int puntos) {
		String cadena = "";
		try {
			//Si llega a 100... }:P
			if (puntos > 99) {
				throw new BOOMException("100 puntos!!");
			}
		
			cadena = puntos>=10?String.valueOf(puntos):"0" + puntos;
		
		} catch(BOOMException be) {
			System.err.println("uouo: " + be.getMensaje());
			System.exit(-1);
		}
		
		return cadena;
	}
	
	private void dibujaMundo() {
		tablero.dibujar(buffer.getDrawGraphics());
		this.dibujarMarcador();
		buffer.getDrawGraphics().drawImage(imagenes.getImagen("salir"), BOTON_SALIR_X-10, BOTON_SALIR_Y-6, this);
		buffer.show();
	}
	
	
	//Pone un mensaje al terminar la partida en pantalla esperando click
	//de ratón para continuar.
	private void dibujarMensajeEnPantalla(String mensaje) {
	    esperandoClick = true;
	    while(esperandoClick) {
		    tiempoInicio = System.currentTimeMillis();
			tablero.dibujar(buffer.getDrawGraphics());
			this.dibujarMarcador();
			buffer.getDrawGraphics().drawImage(imagenes.getImagen(mensaje), MENSAJE_X, MENSAJE_Y, this);
			buffer.show();
	        do {
				Thread.yield();
			} while(System.currentTimeMillis() - tiempoInicio < RPS);
		}
	}
	
	private void dibujarMarcador() {
		String puntosString = convertirNumeroCadena(partidasGanadasJugador);
		
		//Puntos del jugador...
		buffer.getDrawGraphics().drawImage(imagenes.getImagen(puntosString.charAt(0) + ""), MARCADOR_JUGADOR_X, MARCADOR_JUGADOR_Y, this);
		buffer.getDrawGraphics().drawImage(imagenes.getImagen(puntosString.charAt(1) + ""), MARCADOR_JUGADOR_X + imagenes.getImagen("0").getWidth() + 5, MARCADOR_JUGADOR_Y, this);
		
		buffer.getDrawGraphics().drawImage(imagenes.getImagen("equis".equals(fichaJugador)?"miniX":"miniO"), MINI_JUGADOR_X, MINI_JUGADOR_Y, this);
		
		//Puntos del ordenador...
		puntosString = convertirNumeroCadena(partidasGanadasOrdenador);
		buffer.getDrawGraphics().drawImage(imagenes.getImagen(puntosString.charAt(0) + ""), MARCADOR_ORDENADOR_X, MARCADOR_ORDENADOR_Y, this);
		buffer.getDrawGraphics().drawImage(imagenes.getImagen(puntosString.charAt(1) + ""), MARCADOR_ORDENADOR_X + imagenes.getImagen("0").getWidth() + 5, MARCADOR_ORDENADOR_Y, this);
		
		buffer.getDrawGraphics().drawImage(imagenes.getImagen("equis".equals(oponente.getNombreFicha())?"miniX":"miniO"), MINI_OPONENTE_X, MINI_OPONENTE_Y, this);
	}
	
	private void sorteoFicha() {
		if (((int)(Math.random() * 100) % 2)==0) {
			this.fichaJugador = "equis";
			oponente.setNombreFicha("circulo");
		} else {
			this.fichaJugador = "circulo";
			oponente.setNombreFicha("equis");
		}
	}
	
	private void sorteoJugarPrimero() {
		if (((int)(Math.random() * 100) % 2)==0) {
			turnoJugador = true;
			oponente.setMiTurno(false);
		} else {
			turnoJugador = false;
			oponente.setMiTurno(true);
		}
	}
	
	private void dibujaMenu() {
		esperandoEleccion = true;
		facilOn = false;
		dificilOn = false;
		while (esperandoEleccion) {
		    tiempoInicio = System.currentTimeMillis();
		    buffer.getDrawGraphics().drawImage(imagenes.getImagen("menu"), 0, 25, this);
		    buffer.getDrawGraphics().drawImage(imagenes.getImagen(facilOn?"facilon":"faciloff"), BOTON_FACIL_X, BOTON_FACIL_Y, this);
		    buffer.getDrawGraphics().drawImage(imagenes.getImagen(dificilOn?"dificilon":"dificiloff"), BOTON_DIFICIL_X, BOTON_DIFICIL_Y, tablero);
		    buffer.show();
		    do {
				Thread.yield();
		    } while (System.currentTimeMillis() - tiempoInicio < RPS);
		}
	}
	
	private void sumarPunto(String ganador) {
		if (ganador.equals(fichaJugador)) {
			partidasGanadasJugador++;
		} else {
			partidasGanadasOrdenador++;
		}
	}

	public void comienzaJuego() {
		if (!sonidos.estaTocando()) {
			sonidos.tocaSonido("musica2", true);
		}
		dibujaMenu();
		this.inicializaJuego(dificilOn);
		salir = false;
		while (!salir) {
			jugando = true;
			resultadoPartida = TicTacToe.JUGANDOSE;
			
			while (resultadoPartida == TicTacToe.JUGANDOSE && !salir) {
			    tiempoInicio = System.currentTimeMillis();
			    if (oponente.esMiTurno() && resultadoPartida == TicTacToe.JUGANDOSE) {
				    tablero.dibujarFicha(buffer.getDrawGraphics(), oponente.getNombreFicha(), oponente.casillaElegida());
				    resultadoPartida = tablero.compruebaTablero();
				    turnoJugador = true;
			    }

			    this.dibujaMundo();
			    do {
					Thread.yield();
			    } while (System.currentTimeMillis() - tiempoInicio < RPS);
			}
			
			switch (resultadoPartida) {
				case 0:
					//empate
					dibujarMensajeEnPantalla("empate");
					break;
				case -1:
					//ganan x
					sumarPunto(Casilla.X);
					dibujarMensajeEnPantalla(Casilla.X.equals(fichaJugador)?"ganar":"perder");
					break;
				case 1:
					//ganan o
					sumarPunto(Casilla.O);
					dibujarMensajeEnPantalla(Casilla.O.equals(fichaJugador)?"ganar":"perder");
					break;
			}
			
			tablero.limpiaTablero();
			tablero.dibujar(buffer.getDrawGraphics());
		}
	}

	public void inicializaJuego(boolean dificil) {
		tablero = new Tablero(this.imagenes);
		
		resultadoPartida = TicTacToe.JUGANDOSE;

		jugando = true;
		partidasGanadasJugador = 0;
		partidasGanadasOrdenador = 0;
		
		//Elegimos al oponente según la dificultad seleccionada.
		if (dificil) {
			oponente = new OponenteListo(tablero);
		} else {
			oponente = new OponenteTontorron(tablero);

		}
		
		//Sorteo para ver que ficha le toca a cada contendiente...
		this.sorteoFicha();
		
		//Quién comienza a jugar?
		this.sorteoJugarPrimero();
	}

	@Override
	public void paint(Graphics g) {
	}

	public void mouseClicked(MouseEvent event) {
		if (esperandoEleccion) {
			if (event.getButton() == MouseEvent.BUTTON1) {
				if (event.getX() >= BOTON_SALIR_X && event.getY() >= BOTON_SALIR_Y &&
					event.getX() <= BOTON_SALIR_X + 35 && event.getY() <= BOTON_SALIR_Y + 35) {
						//Quiere salir del juego.... :"(
						this.salirJuego(0);
				} else if (facilOn || dificilOn) {
					//Si el click ha sido sobre el botón de fácil o difícil... queremos jugar!!
					esperandoEleccion = false;
				}
				
			}
		} else if (event.getButton() == MouseEvent.BUTTON1 && turnoJugador &&
						tablero.dibujarFicha(buffer.getDrawGraphics(), fichaJugador, event.getPoint())) {
			sonidos.tocaSonido("pock", false);
			resultadoPartida = tablero.compruebaTablero();
			turnoJugador = false;
			oponente.setMiTurno(true);
		} else if (event.getButton() == MouseEvent.BUTTON1 && turnoJugador &&
					event.getX()>=BOTON_SALIR_X && event.getY()>=BOTON_SALIR_Y &&
					event.getX()<=BOTON_SALIR_X + 35 && event.getY()<=BOTON_SALIR_Y + 35) {
				jugando = false;
				salir = true;
		} else if (esperandoClick) {
			esperandoClick = false;
		}
	}

	public void mousePressed(MouseEvent event) {
	}

	public void mouseReleased(MouseEvent event) {
	}

	public void mouseEntered(MouseEvent event) {
	
	}

	public void mouseExited(MouseEvent event) {
	}
	
	public void mouseDragged(MouseEvent event) {
	}

	public void mouseMoved(MouseEvent event) {
			if (esperandoEleccion) {
			if (event.getX() >= BOTON_FACIL_X && event.getY() >= BOTON_FACIL_Y &&
					event.getX() <= BOTON_FACIL_X + 116 && event.getY() <= BOTON_FACIL_Y + 99) {
				facilOn = true;
			} else if (event.getX() >= BOTON_DIFICIL_X && event.getY() >= BOTON_DIFICIL_Y &&
					event.getX() <= BOTON_DIFICIL_X + 131 && event.getY() <= BOTON_DIFICIL_Y + 119) {
				dificilOn = true;
			} else {
				facilOn = false;
				dificilOn = false;
			}
		}
	}

	public final static void main(String[] args) {
		TicTacToe ttt = new TicTacToe();
		while (true) {
			ttt.comienzaJuego();
		}
	}
}
